﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.IO;

namespace BBCDiscTransfer
{

    public partial class MainForm : Form
    {
        public static bool Abort;

        private List<int> bytes = new List<int>();
        private StringBuilder buffer = new StringBuilder();
        private ListViewItem currentItem;
        private bool busy;

        public MainForm()
        {
            InitializeComponent();
            TargetFolder.Text = @"C:\Users\kemals\Documents\BeebEm\DiscIms";
        }

        private void Transfer_Click(object sender, EventArgs e)
        {
            try
            {
                int drive = Convert.ToInt32(DriveSelector.Value);
                TransferDrive(drive);
            }
            catch (Exception ex)
            {
                SetMessage(ex.Message);
            }
        }

        private void DriveContents_Click(object sender, EventArgs e)
        {
            try
            {
                int drive = Convert.ToInt32(DriveSelector.Value);
                GetDiskContents(drive);
            }
            catch (Exception ex)
            {
                SetMessage(ex.Message);
            }
        }

        private void TestLinkButton_Click(object sender, EventArgs e)
        {
            if (busy || Abort) return;
        }

        private void AbortTransfer_Click(object sender, EventArgs e)
        {
            Abort = true;
            busy = false;
        }

        private void SelectFolder_Click(object sender, EventArgs e)
        {
            try
            {
                using (var folderDialog = new FolderBrowserDialog())
                {
                    folderDialog.SelectedPath = TargetFolder.Text;
                    folderDialog.ShowNewFolderButton = true;
                    if (folderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        TargetFolder.Text = folderDialog.SelectedPath;
                    }
                }
            }
            catch (Exception ex)
            {
                SetMessage(ex.Message);
            }
        }

        private void TransferDrive(int drive)
        {
            if (busy) return;
            Abort = false;
            busy = true;
            try
            {
                var folder = TargetFolder.Text;
                if (!Directory.Exists(folder)) Directory.CreateDirectory(folder);
                var result = TransferDisk(drive, folder);
            }
            finally
            {
                busy = false;
            }
        }

        private string TransferDisk(int drive, string folder)
        {
            var files = GetDiskContents(drive);
            var infText = string.Empty;
            for (int i = 0; i < files.Count; i++)
            {
                if (Abort) break;
                var file = files[i];
                var item = fileList.Items[file.Name];
                item.SubItems[4].Text = "Transferring";
                currentItem = item;
                fileList.Refresh();
                Application.DoEvents();
                var result = TransferFile(file, folder, Progress);
                var infPath = folder + "\\" + file.Name + ".INF";
                System.IO.File.WriteAllText(infPath, file.ToString() + "\r");
                item.SubItems[4].Text = infPath; // result;
                item.Refresh();
                Application.DoEvents(); // Hack to buy more fluid UI. Should use a Task
            }

            return "";
        }

        private List<FileInfo> GetDiskContents(int drive)
        {
            fileList.Items.Clear();
            var fileInfos = new List<FileInfo>();
            SetMessage("Reading drive " + drive);
            var info = GetDiskInfo(drive);
            if (info.Contains("Not found"))
            {
                SetMessage("Drive empty or not formatted");
                return fileInfos;
            }
            else
            {
                MessageOff();
            }
            var files = info.Split('\r');
            // NOTE:
            // first line of info is the INFO command.
            // last line is the blank line of the next cursor
            // each line ends with \n
            for (int i = 1; i < files.Length - 1; i++)
            {
                if (!files[i].StartsWith("*"))
                {
                    var file = new FileInfo(files[i]);
                    var listItem = new ListViewItem(new string[] { file.Name, file.Load, file.Call, file.Size, "Pending" });
                    listItem.Name = file.Name;
                    fileList.Items.Add(listItem);
                    fileInfos.Add(file);
                }
            }
            fileList.Refresh();
            return fileInfos;
        }

        private void SetMessage(string text)
        {
            message.Text = text;
            message.Visible = true;
            message.Refresh();
        }

        private void MessageOff()
        {
            message.Visible = false;
        }

        private void Progress(int bytes)
        {
            if (bytes % 100 == 0)
            {
                currentItem.SubItems[4].Text = "Transferring (" + bytes + " bytes)";
                currentItem.Refresh();
            }
        }

        private static string GetDiskInfo(int drive)
        {
            using (var serial = new SerialPort("COM1"))
            {
                try
                {
                    serial.ReadTimeout = 1000;
                    serial.BaudRate = 9600;
                    serial.DtrEnable = true;
                    serial.Open();
                    serial.DiscardOutBuffer();
                    serial.Write("*FX 8,7\r");
                    serial.Write("*FX 3,1");
                    serial.SendCommand("");
                    serial.SendCommand("*DRIVE " + drive.ToString());
                    serial.ReadString();
                    serial.Write("*INFO *.*\r");
                    return serial.ReadString();
                    //return serial.SendCommand("*INFO *.*");
                }
                finally
                {
                    serial.Close();
                }
            }
        }

        private static string TransferFile(FileInfo file, string folder, Action<int> progress)
        {
            using (var serial = new SerialPort("COM1"))
            {
                try
                {
                    serial.ReadTimeout = 1000;
                    serial.BaudRate = 9600;
                    serial.DtrEnable = true;
                    serial.Open();
                    var b = serial.GetFile(file.Name.Trim(), progress);
                    System.IO.File.WriteAllBytes(folder + "\\" + file.Name, b);
                    return file.Name + ": Success";
                }
                catch (Exception e)
                {
                    return file.Name + ": " + e.Message;
                }
            }
        }

        private void MainForm_Load(object sender, EventArgs e)
        {

        }

    }

}

